package com.base.library.widget

import android.content.Context
import android.content.res.TypedArray
import android.text.TextUtils
import android.util.AttributeSet
import android.view.*
import android.widget.FrameLayout
import android.widget.TextView
import androidx.annotation.IntDef
import com.base.library.R
import com.base.library.utils.FastClickUtil.Companion.click

/**
 * 状态布局
 */
open class MultipleStatusView constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int, defStyleRes: Int
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes) {
    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(
        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int
    ) : this(context, attrs, defStyleAttr, 0)

    private var mEmptyView: View? = null
    private var mErrorView: View? = null
    private var mLoadingView: View? = null
    private var mNoNetworkView: View? = null
    private val mEmptyViewResId: Int
    private val mErrorViewResId: Int
    private val mLoadingViewResId: Int
    private val mNoNetworkViewResId: Int

    /**
     * 获取当前状态
     *
     * @return 视图状态
     */
    var viewStatus = -1
        private set
    private val mInflater: LayoutInflater
    private var mOnRetryClickListener: OnClickListener? = null
    private var mViewStatusListener: OnViewStatusChangeListener? = null

    private val mErrorViewLayoutParams by lazy {
        LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT
        ).apply {
            gravity = Gravity.CENTER
        }
    }
    private val mLoadingViewLayoutParams by lazy {
        LayoutParams(
            LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT
        ).apply {
            gravity = Gravity.CENTER
        }
    }

    /**
     * 非content状态下 布局的id
     */
    private val mOtherIds = arrayListOf<Int>()

    init {
        val a: TypedArray = context.obtainStyledAttributes(
            attrs, R.styleable.MultipleStatusView, 0, 0
        )
        mEmptyViewResId = a.getResourceId(
            R.styleable.MultipleStatusView_emptyViewResId, R.layout.layout_empty_view
        )
        mErrorViewResId = a.getResourceId(
            R.styleable.MultipleStatusView_errorViewResId, R.layout.layout_error_view
        )
        mLoadingViewResId = a.getResourceId(
            R.styleable.MultipleStatusView_loadingViewResId, R.layout.layout_refresh
        )
        mNoNetworkViewResId = a.getResourceId(
            R.styleable.MultipleStatusView_noNetworkViewResId, R.layout.layout_error_view
        )
        a.recycle()
        mInflater = LayoutInflater.from(getContext())
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        showContent()
    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        if (mOtherIds.isNotEmpty()) {
            mOtherIds.clear()
        }
        mOnRetryClickListener = null
        mViewStatusListener = null
    }

    /**
     * 设置重试点击事件
     *
     * @param onRetryClickListener 重试点击事件
     */
    fun setOnRetryClickListener(onRetryClickListener: OnClickListener?) {
        mOnRetryClickListener = onRetryClickListener
    }

    /**
     * 显示空视图
     *
     * @param hint 自定义提示文本内容
     */
    fun showEmpty() {
        showEmpty(null)
    }

    /**
     * 显示空视图
     *
     * @param hint 自定义提示文本内容
     */
    fun showEmpty(hint: String? = null) {
        showEmpty(mEmptyViewResId, mErrorViewLayoutParams)
        setStatusHintContent(mEmptyView, hint)
    }

    /**
     * 显示空视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    fun showEmpty(
        layoutId: Int, layoutParams: ViewGroup.LayoutParams?
    ) {
        if (layoutId != mEmptyViewResId) {
            mEmptyView = null
        }
        showEmpty(if (null == mEmptyView) inflateView(layoutId) else mEmptyView!!, layoutParams)
    }

    /**
     * 显示空视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    private fun showEmpty(view: View, layoutParams: ViewGroup.LayoutParams?) {
        checkNull(view, "Empty view is null.")
        checkNull(layoutParams, "Layout params is null.")
        changeViewStatus(State.STATUS_EMPTY)
        if (null == mEmptyView) {
            mEmptyView = view
            view.findViewById<View?>(R.id.btn_retry_view)?.click {
                mOnRetryClickListener?.onClick(it)
            }
            addView(view, 0, layoutParams)
            mOtherIds.add(view.id)
        }
        showViewById(view.id)
    }

    /**
     * 显示错误视图
     *
     */
    fun showError() {
        showError(null)
    }

    /**
     * 显示错误视图
     *
     * @param hint 自定义提示文本内容
     */
    fun showError(hint: String?, btnText: String? = null) {
        showError(mErrorViewResId, mErrorViewLayoutParams)
        setStatusHintContent(mErrorView, hint)
        setButtonContent(mErrorView, btnText)
    }

    /**
     * 显示错误视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    fun showError(
        layoutId: Int, layoutParams: ViewGroup.LayoutParams?
    ) {
        if (layoutId != mErrorViewResId) {
            mErrorView = null
        }
        showError(if (null == mErrorView) inflateView(layoutId) else mErrorView!!, layoutParams)
    }

    /**
     * 显示错误视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    private fun showError(view: View, layoutParams: ViewGroup.LayoutParams?) {
        checkNull(view, "Error view is null.")
        checkNull(layoutParams, "Layout params is null.")
        changeViewStatus(State.STATUS_ERROR)
        if (null == mErrorView) {
            mErrorView = view
            view.findViewById<View?>(R.id.btn_retry_view)?.click {
                mOnRetryClickListener?.onClick(it)
            }
            addView(view, 0, layoutParams)
            mOtherIds.add(view.id)
        }
        showViewById(view.id)

    }

    /**
     * 显示加载中视图
     *
     */
    fun showLoading() {
        showLoading(null)
    }

    /**
     * 显示加载中视图
     *
     * @param hint 自定义提示文本内容
     */
    fun showLoading(hint: String?) {
        showLoading(mLoadingViewResId, mLoadingViewLayoutParams)
        setStatusHintContent(mLoadingView, hint)
    }

    /**
     * 显示加载中视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    fun showLoading(
        layoutId: Int, layoutParams: ViewGroup.LayoutParams?
    ) {
        if (layoutId != mLoadingViewResId) {
            mLoadingView = null
        }
        showLoading(
            if (null == mLoadingView) inflateView(layoutId) else mLoadingView!!, layoutParams
        )
    }

    /**
     * 显示加载中视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    private fun showLoading(view: View, layoutParams: ViewGroup.LayoutParams?) {
        checkNull(view, "Loading view is null.")
        checkNull(layoutParams, "Layout params is null.")
        changeViewStatus(State.STATUS_LOADING)
        if (null == mLoadingView) {
            mLoadingView = view
            addView(view, 0, layoutParams)
            mOtherIds.add(view.id)
        }
        showViewById(view.id)
    }

    /**
     * 显示无网络视图
     *
     */
    fun showNoNetwork() {
        showNoNetwork(null)
    }

    /**
     * 显示无网络视图
     *
     * @param hint 自定义提示文本内容
     */
    fun showNoNetwork(hint: String?, btnText: String? = null) {
        showNoNetwork(mNoNetworkViewResId, mErrorViewLayoutParams)
        setStatusHintContent(mNoNetworkView, hint)
        setButtonContent(mErrorView, btnText)
    }

    /**
     * 显示无网络视图
     *
     * @param layoutId     自定义布局文件
     * @param layoutParams 布局参数
     */
    fun showNoNetwork(
        layoutId: Int, layoutParams: ViewGroup.LayoutParams?
    ) {
        if (layoutId != mNoNetworkViewResId) {
            mNoNetworkView = null
        }
        showNoNetwork(
            if (null == mNoNetworkView) inflateView(layoutId) else mNoNetworkView!!, layoutParams
        )
    }

    /**
     * 显示无网络视图
     *
     * @param view         自定义视图
     * @param layoutParams 布局参数
     */
    private fun showNoNetwork(view: View, layoutParams: ViewGroup.LayoutParams?) {
        checkNull(view, "Loading view is null.")
        checkNull(layoutParams, "Layout params is null.")
        changeViewStatus(State.STATUS_NETWORK_ERROR)
        if (null == mNoNetworkView) {
            mNoNetworkView = view
            view.findViewById<View?>(R.id.btn_retry_view)?.click {
                mOnRetryClickListener?.onClick(it)
            }
            addView(view, 0, layoutParams)
            mOtherIds.add(view.id)
        }
        showViewById(view.id)
    }

    override fun addView(child: View, index: Int, params: ViewGroup.LayoutParams?) {
        if (child.id == -1) {
            child.id = generateViewId()
        }
        super.addView(child, index, params)
    }

    /**
     * 显示内容视图
     */
    fun showContent() {
        changeViewStatus(State.STATUS_CONTENT)
        showContentView()
    }

    private fun setStatusHintContent(view: View?, hint: String?) {
        checkNull(view, "Target view is null.")
        if (TextUtils.isEmpty(hint)) {
            return
        }
        val hintView: TextView? = view?.findViewById(R.id.tv_status_hint_content)
        hintView?.apply {
            text = hint
        }
    }

    private fun setButtonContent(view: View?, btnText: String?) {
        checkNull(view, "Target view is null.")
        if (TextUtils.isEmpty(btnText)) {
            return
        }
        val btn: TextView? = view?.findViewById(R.id.btn_retry_view)
        btn?.apply {
            text = btnText
        }
    }

    private fun inflateView(layoutId: Int): View {
        return mInflater.inflate(layoutId, null)
    }

    private fun showViewById(viewId: Int) {
        val childCount: Int = childCount
        for (i in 0 until childCount) {
            val view: View = getChildAt(i)
            view.visibility = if (view.id == viewId) View.VISIBLE else View.GONE
        }
    }

    private fun showContentView() {
        val childCount: Int = childCount
        for (i in 0 until childCount) {
            val view: View = getChildAt(i)
            // 非content里面的布局给隐藏掉即mOtherIds包含的布局  其他的显示
            view.visibility = if (mOtherIds.contains(view.id)) View.GONE else View.VISIBLE
        }
    }

    private fun checkNull(target: Any?, hint: String) {
        if (null == target) {
            throw NullPointerException(hint)
        }
    }

    /**
     * 视图状态改变接口
     */
    interface OnViewStatusChangeListener {
        /**
         * 视图状态改变时回调
         *
         * @param oldViewStatus 之前的视图状态
         * @param newViewStatus 新的视图状态
         */
        fun onChange(@State oldViewStatus: Int, @State newViewStatus: Int)
    }

    /**
     * 设置视图状态改变监听事件
     *
     * @param onViewStatusChangeListener 视图状态改变监听事件
     */
    fun setOnViewStatusChangeListener(onViewStatusChangeListener: OnViewStatusChangeListener?) {
        mViewStatusListener = onViewStatusChangeListener
    }

    /**
     * 改变视图状态
     *
     * @param newViewStatus 新的视图状态
     */
    private fun changeViewStatus(newViewStatus: Int) {
        if (viewStatus == newViewStatus) {
            return
        }
        mViewStatusListener?.onChange(viewStatus, newViewStatus)
        viewStatus = newViewStatus
    }

    @IntDef(
        State.STATUS_CONTENT,
        State.STATUS_LOADING,
        State.STATUS_EMPTY,
        State.STATUS_ERROR,
        State.STATUS_NETWORK_ERROR
    )
    @Retention(AnnotationRetention.SOURCE)
    annotation class State {
        companion object {
            /**
             * 内容显示状态
             */
            const val STATUS_CONTENT = 0x00

            /**
             * loading状态
             */
            const val STATUS_LOADING = 0x01

            /**
             * 无数据状态
             */
            const val STATUS_EMPTY = 0x02

            /**
             * 错误状态
             */
            const val STATUS_ERROR = 0x03

            /**
             * 网络异常
             */
            const val STATUS_NETWORK_ERROR = 0x04
        }
    }
}